// 使用Set，不会在副作用函数和被操作的目标之间建立明确的联系
const bucket = new WeakMap()

// 原始数据
const data = {
  ok: true,
  text: 'vue',
}

// 对原始数据的代理
const obj = new Proxy(data, {
  // 拦截读取操作 
  get(target, key) {
    track(target, key)
    // 返回属性值
    return target[key]
  },
  // 拦截设置操作
  set(target, key, newVal) {
    cleanup(effectFn) //清除
    // 设置属性值
    target[key] = newVal
    trigger(target, key)
  }
})

// 在get拦截函数内调用track函数追踪变化
function track(target, key) {
  if (!activeEffect) return target[key]
  // 取出target目标对象
  let depsMap = bucket.get(target)
  if (!depsMap) {
    bucket.set(target, (depsMap = new Map()))
  }
  // 取出key
  let deps = depsMap.get(key)
  if (!deps) {
    depsMap.set(key, (deps = new Set()))
  }
  deps.add(affectEffect)
  activeEffect.deps.push(deps)
}

// 在set拦截函数内调用trigger函数追踪变化
function trigger(target, key) {
  const depsMap = bucket.get(target)
  if (!depsMap) return
  // 把副作用函数从桶中取出并执行
  const effects = depsMap.get(key)
  effects && effects.forEach(fn => fn())
}

function cleanup(effectFn) {
  for (let i = 0; i < effectFn.deps.length; i++) {
    const deps = effectFn.deps[i]
    deps.delete(effectFn)
  }
  effectFn.deps.length = 0
}

// 存储被注册的副作用函数
let activeEffect
function effect(fn) {
  const effectFn = () => {
    affectEffect = effectFn
    // 执行副作用函数
    fn()
  }
  effectFn.deps = []
  effectFn()
}

effect(() => document.body.innerText = obj.text)